<!DOCTYPE html>



  


<html class="theme-next gemini use-motion" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />



  <meta name="google-site-verification" content="true" />














  
  
    
  
  <link href="//cdn.jsdelivr.net/fancybox/2.1.5/jquery.fancybox.min.css" rel="stylesheet" type="text/css" />




  
  
  
  

  
    
    
  

  

  

  

  

  
    
    
    <link href="//fonts.lug.ustc.edu.cn/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






  

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.2" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="RESTful," />








  <link rel="shortcut icon" type="image/x-icon" href="/images/favicon.ico?v=5.1.2" />






<meta name="keywords" content="RESTful">
<meta property="og:type" content="article">
<meta property="og:title" content="RESTful API收集整理">
<meta property="og:url" content="http://hunfan.top/2018/09/06/RESTful-API收集整理/index.html">
<meta property="og:site_name" content="混饭&#39;s Notes">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="http://hunfan.top/upload/homePage/20180906170330.jpg">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/7477749-c6fdcdc835d413f7?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:updated_time" content="2019-01-10T02:53:53.374Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="RESTful API收集整理">
<meta name="twitter:image" content="http://hunfan.top/upload/homePage/20180906170330.jpg">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Gemini',
    version: '5.1.2',
    sidebar: {"position":"left","display":"post","offset":12,"offset_float":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '77ZW8HG1F0',
      apiKey: '924aaf9b16831d3af864330abb1b94cf',
      indexName: 'github',
      hits: {"per_page":10},
      labels: {"input_placeholder":"输入关键词进行搜索","hits_empty":"找不到关于” ${query} ”的文章","hits_stats":"共找到 ${hits} 篇文章，花了 ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://hunfan.top/2018/09/06/RESTful-API收集整理/"/>



<script>
    (function(){
        if(''){
            if (prompt('请输入文章密码') !== ''){
                alert('密码错误！');
                history.back();
            }
        }
    })();
</script>



	<meta name="google-site-verification" content="7cmTqceXKE0HPzXSCTPWvChlMw-OZuC3GLENr9qj9XM" />


  <title>RESTful API收集整理 | 混饭's Notes</title>
  








</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>
	<a target="_blank" href="https://github.com/hf-hf" class="github-corner" aria-label="Fork me on GitHub"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#151513; color:#fff; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>
	
    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">混饭's Notes</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">Quick notes</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      

      
        <li class="menu-item menu-item-search">
          
            <a href="javascript:;" class="popup-trigger">
          
            
              <i class="menu-item-icon fa fa-search fa-fw"></i> <br />
            
            搜索
          </a>
        </li>
      
    </ul>
  

  
    <div class="site-search">
      
  
  <div class="algolia-popup popup search-popup">
    <div class="algolia-search">
      <div class="algolia-search-input-icon">
        <i class="fa fa-search"></i>
      </div>
      <div class="algolia-search-input" id="algolia-search-input"></div>
    </div>

    <div class="algolia-results">
      <div id="algolia-stats"></div>
      <div id="algolia-hits"></div>
      <div id="algolia-pagination" class="algolia-pagination"></div>
    </div>

    <span class="popup-btn-close">
      <i class="fa fa-times-circle"></i>
    </span>
  </div>




    </div>
  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://hunfan.top/2018/09/06/RESTful-API收集整理/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="混饭">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.png">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="混饭's Notes">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">RESTful API收集整理</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2018-09-06T15:48:34+08:00">
                2018-09-06
              </time>
            

            

            
          </span>

          

          
            
          

          
          
             <span id="/2018/09/06/RESTful-API收集整理/" class="leancloud_visitors" data-flag-title="RESTful API收集整理">
               <span class="post-meta-divider">|</span>
               <span class="post-meta-item-icon">
                 <i class="fa fa-eye"></i>
               </span>
               
                 <span class="post-meta-item-text">阅读次数&#58;</span>
               
                 <span class="leancloud-visitors-count"></span>
             </span>
          

          

          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p><img src="/upload/homePage/20180906170330.jpg" alt="homePage"><br><a id="more"></a></p>
<h1 id="RESTful-API"><a href="#RESTful-API" class="headerlink" title="RESTful API"></a>RESTful API</h1><h1 id="路径定义"><a href="#路径定义" class="headerlink" title="路径定义"></a>路径定义</h1><h2 id="版本号"><a href="#版本号" class="headerlink" title="版本号"></a>版本号</h2><p>在 RESTful API 中，API 接口应该尽量兼容之前的版本。但是，在实际业务开发场景中，可能随着业务需求的不断迭代，现有的 API 接口无法支持旧版本的适配，此时如果强制升级服务端的 API 接口将导致客户端旧有功能出现故障。实际上，Web 端是部署在服务器，因此它可以很容易为了适配服务端的新的 API 接口进行版本升级，然而像 Android 端、IOS 端、PC 端等其他客户端是运行在用户的机器上，因此当前产品很难做到适配新的服务端的 API 接口，从而出现功能故障，这种情况下，用户必须升级产品到最新的版本才能正常使用。</p>
<p>为了解决这个版本不兼容问题，在设计 RESTful API 的一种实用的做法是使用版本号。一般情况下，我们会在 url 中保留版本号，并同时兼容多个版本。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">【GET】  /v1/users/&#123;user_id&#125;  // 版本 v1 的查询用户列表的 API 接口</span><br><span class="line">【GET】  /v2/users/&#123;user_id&#125;  // 版本 v2 的查询用户列表的 API 接口</span><br></pre></td></tr></table></figure>
<p>现在，我们可以不改变版本 v1 的查询用户列表的 API 接口的情况下，新增版本 v2 的查询用户列表的 API 接口以满足新的业务需求，此时，客户端的产品的新功能将请求新的服务端的 API 接口地址。虽然服务端会同时兼容多个版本，但是同时维护太多版本对于服务端而言是个不小的负担，因为服务端要维护多套代码。这种情况下，常见的做法不是维护所有的兼容版本，而是只维护最新的几个兼容版本，例如维护最新的三个兼容版本。在一段时间后，当绝大多数用户升级到较新的版本后，废弃一些使用量较少的服务端的老版本API 接口版本，并要求使用产品的非常旧的版本的用户强制升级。</p>
<p>注意的是，“不改变版本 v1 的查询用户列表的 API 接口”主要指的是对于客户端的调用者而言它看起来是没有改变。而实际上，如果业务变化太大，服务端的开发人员需要对旧版本的 API 接口使用适配器模式将请求适配到新的API 接口上。</p>
<h2 id="资源路径"><a href="#资源路径" class="headerlink" title="资源路径"></a>资源路径</h2><p>RESTful API 的设计以资源为核心，每一个 URI 代表一种资源。因此，URI 不能包含动词，只能是名词。注意的是，形容词也是可以使用的，但是尽量少用。一般来说，不论资源是单个还是多个，API 的名词要以复数进行命名。此外，命名名词的时候，要使用小写、数字及下划线来区分多个单词。这样的设计是为了与 json 对象及属性的命名方案保持一致。例如，一个查询系统标签的接口可以进行如下设计。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">【GET】  /v1/tags/&#123;tag_id&#125;</span><br></pre></td></tr></table></figure>
<p>同时，资源的路径应该从根到子依次如下。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/&#123;resources&#125;/&#123;resource_id&#125;/&#123;sub_resources&#125;/&#123;sub_resource_id&#125;/&#123;sub_resource_property&#125;</span><br></pre></td></tr></table></figure>
<p>我们来看一个“添加用户的角色”的设计，其中“用户”是主资源，“角色”是子资源。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">【POST】  /v1/users/&#123;user_id&#125;/roles/&#123;role_id&#125; // 添加用户的角色</span><br></pre></td></tr></table></figure>
<p>有的时候，当一个资源变化难以使用标准的 RESTful API 来命名，可以考虑使用一些特殊的 actions 命名。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">/&#123;resources&#125;/&#123;resource_id&#125;/actions/&#123;action&#125;</span><br></pre></td></tr></table></figure>
<p>举个例子，“密码修改”这个接口的命名很难完全使用名词来构建路径，此时可以引入 action 命名。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">【PUT】  /v1/users/&#123;user_id&#125;/password/actions/modify // 密码修改</span><br></pre></td></tr></table></figure>
<p>当路径中出现多个单词时，请使用中划线 <code>-</code> 来连接。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">【GET】  /v1/order/my-orders // 获取我的订单信息</span><br></pre></td></tr></table></figure>
<h2 id="请求方式"><a href="#请求方式" class="headerlink" title="请求方式"></a>请求方式</h2><p>可以通过 GET、 POST、 PUT、 PATCH、 DELETE 等方式对服务端的资源进行操作。其中，GET 用于查询资源，POST 用于创建资源，PUT 用于更新服务端的资源的全部信息，PATCH 用于更新服务端的资源的部分信息，DELETE 用于删除服务端的资源。</p>
<p>这里，笔者使用“用户”的案例进行回顾通过 GET、 POST、 PUT、 PATCH、 DELETE 等方式对服务端的资源进行操作。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">【GET】          /users                # 查询用户信息列表</span><br><span class="line">【GET】          /users/1001           # 查看某个用户信息</span><br><span class="line">【POST】         /users                # 新建用户信息</span><br><span class="line">【PUT】          /users/1001           # 更新用户信息(全部字段)</span><br><span class="line">【PATCH】        /users/1001           # 更新用户信息(部分字段)</span><br><span class="line">【DELETE】       /users/1001           # 删除用户信息</span><br></pre></td></tr></table></figure>
<h2 id="查询参数"><a href="#查询参数" class="headerlink" title="查询参数"></a>查询参数</h2><p>RESTful API 接口应该提供参数，过滤返回结果。其中，offset 指定返回记录的开始位置。一般情况下，它会结合 limit 来做分页的查询，这里 limit 指定返回记录的数量。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">【GET】  /&#123;version&#125;/&#123;resources&#125;/&#123;resource_id&#125;?offset=0&amp;limit=20</span><br></pre></td></tr></table></figure>
<p>同时，orderby 可以用来排序，但仅支持单个字符的排序，如果存在多个字段排序，需要业务中扩展其他参数进行支持。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">【GET】  /&#123;version&#125;/&#123;resources&#125;/&#123;resource_id&#125;?orderby=&#123;field&#125; [asc|desc]</span><br></pre></td></tr></table></figure>
<p>为了更好地选择是否支持查询总数，我们可以使用 count 字段，count 表示返回数据是否包含总条数，它的默认值为 false。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">【GET】  /&#123;version&#125;/&#123;resources&#125;/&#123;resource_id&#125;?count=[true|false]</span><br></pre></td></tr></table></figure>
<p>上面介绍的 offset、 limit、 orderby 是一些公共参数。此外，业务场景中还存在许多个性化的参数。我们来看一个例子。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">【GET】  /v1/categorys/&#123;category_id&#125;/apps/&#123;app_id&#125;?enable=[1|0]&amp;os_type=&#123;field&#125;&amp;device_ids=&#123;field,field,…&#125;</span><br></pre></td></tr></table></figure>
<p>注意的是，不要过度设计，只返回用户需要的查询参数。此外，需要考虑是否对查询参数创建数据库索引以提高查询性能。</p>
<h2 id="状态码"><a href="#状态码" class="headerlink" title="状态码"></a>状态码</h2><p>使用适合的状态码很重要，而不应该全部都返回状态码 200，或者随便乱使用。这里，列举笔者在实际开发过程中常用的一些状态码，以供参考。</p>
<table>
<thead>
<tr>
<th>状态码</th>
<th style="text-align:right">描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>200</td>
<td style="text-align:right">请求成功</td>
</tr>
<tr>
<td>201</td>
<td style="text-align:right">创建成功</td>
</tr>
<tr>
<td>400</td>
<td style="text-align:right">错误的请求</td>
</tr>
<tr>
<td>401</td>
<td style="text-align:right">未验证</td>
</tr>
<tr>
<td>403</td>
<td style="text-align:right">被拒绝</td>
</tr>
<tr>
<td>404</td>
<td style="text-align:right">无法找到</td>
</tr>
<tr>
<td>409</td>
<td style="text-align:right">资源冲突</td>
</tr>
<tr>
<td>500</td>
<td style="text-align:right">服务器内部错误</td>
</tr>
</tbody>
</table>
<h2 id="异常响应"><a href="#异常响应" class="headerlink" title="异常响应"></a>异常响应</h2><p>当 RESTful API 接口出现非 2xx 的 HTTP 错误码响应时，采用全局的异常结构响应信息。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.1 400 Bad Request</span><br><span class="line">Content-Type: application/json</span><br><span class="line">&#123;</span><br><span class="line">    &quot;code&quot;: &quot;INVALID_ARGUMENT&quot;,</span><br><span class="line">    &quot;message&quot;: &quot;&#123;error message&#125;&quot;,</span><br><span class="line">    &quot;cause&quot;: &quot;&#123;cause message&#125;&quot;,</span><br><span class="line">    &quot;request_id&quot;: &quot;01234567-89ab-cdef-0123-456789abcdef&quot;,</span><br><span class="line">    &quot;host_id&quot;: &quot;&#123;server identity&#125;&quot;,</span><br><span class="line">    &quot;server_time&quot;: &quot;2014-01-01T12:00:00Z&quot;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="请求参数"><a href="#请求参数" class="headerlink" title="请求参数"></a>请求参数</h2><p>在设计服务端的 RESTful API 的时候，我们还需要对请求参数进行限制说明。例如一个支持批量查询的接口，我们要考虑最大支持查询的数量。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">【GET】     /v1/users/batch?user_ids=1001,1002      // 批量查询用户信息</span><br><span class="line">参数说明</span><br><span class="line">- user_ids: 用户ID串，最多允许 20 个。</span><br></pre></td></tr></table></figure>
<p>此外，在设计新增或修改接口时，我们还需要在文档中明确告诉调用者哪些参数是必填项，哪些是选填项，以及它们的边界值的限制。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">【POST】     /v1/users                             // 创建用户信息</span><br><span class="line">请求内容</span><br><span class="line">&#123;</span><br><span class="line">    &quot;username&quot;: &quot;lgz&quot;,                 // 必填, 用户名称, max 10</span><br><span class="line">    &quot;realname&quot;: &quot;梁桂钊&quot;,               // 必填, 用户名称, max 10</span><br><span class="line">    &quot;password&quot;: &quot;123456&quot;,              // 必填, 用户密码, max 32</span><br><span class="line">    &quot;email&quot;: &quot;lianggzone@163.com&quot;,     // 选填, 电子邮箱, max 32</span><br><span class="line">    &quot;weixin&quot;: &quot;LiangGzone&quot;,            // 选填，微信账号, max 32</span><br><span class="line">    &quot;sex&quot;: 1                           // 必填, 用户性别[1-男 2-女 99-未知]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="响应参数"><a href="#响应参数" class="headerlink" title="响应参数"></a>响应参数</h2><p>针对不同操作，服务端向用户返回的结果应该符合以下规范。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">【GET】     /&#123;version&#125;/&#123;resources&#125;/&#123;resource_id&#125;      // 返回单个资源对象</span><br><span class="line">【GET】     /&#123;version&#125;/&#123;resources&#125;                    // 返回资源对象的列表</span><br><span class="line">【POST】    /&#123;version&#125;/&#123;resources&#125;                    // 返回新生成的资源对象</span><br><span class="line">【PUT】     /&#123;version&#125;/&#123;resources&#125;/&#123;resource_id&#125;      // 返回完整的资源对象</span><br><span class="line">【PATCH】   /&#123;version&#125;/&#123;resources&#125;/&#123;resource_id&#125;      // 返回完整的资源对象</span><br><span class="line">【DELETE】  /&#123;version&#125;/&#123;resources&#125;/&#123;resource_id&#125;      // 状态码 200，返回完整的资源对象。</span><br><span class="line">                                                      // 状态码 204，返回一个空文档</span><br></pre></td></tr></table></figure>
<p>如果是单条数据，则返回一个对象的 JSON 字符串。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.1 200 OK</span><br><span class="line">&#123;</span><br><span class="line">    &quot;id&quot; : &quot;01234567-89ab-cdef-0123-456789abcdef&quot;,</span><br><span class="line">    &quot;name&quot; : &quot;example&quot;,</span><br><span class="line">    &quot;created_time&quot;: 1496676420000,</span><br><span class="line">    &quot;updated_time&quot;: 1496676420000,</span><br><span class="line">    ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>如果是列表数据，则返回一个封装的结构体。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">HTTP/1.1 200 OK</span><br><span class="line">&#123;</span><br><span class="line">    &quot;count&quot;:100,</span><br><span class="line">    &quot;items&quot;:[</span><br><span class="line">        &#123;</span><br><span class="line">            &quot;id&quot; : &quot;01234567-89ab-cdef-0123-456789abcdef&quot;,</span><br><span class="line">            &quot;name&quot; : &quot;example&quot;,</span><br><span class="line">            &quot;created_time&quot;: 1496676420000,</span><br><span class="line">            &quot;updated_time&quot;: 1496676420000,</span><br><span class="line">            ...</span><br><span class="line">        &#125;,</span><br><span class="line">        ...</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h2 id="一个完整的案例"><a href="#一个完整的案例" class="headerlink" title="一个完整的案例"></a>一个完整的案例</h2><p>最后，我们使用一个完整的案例将前面介绍的知识整合起来。这里，使用“获取用户列表”的案例。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br></pre></td><td class="code"><pre><span class="line">【GET】     /v1/users?[&amp;keyword=xxx][&amp;enable=1][&amp;offset=0][&amp;limit=20] 获取用户列表</span><br><span class="line">功能说明：获取用户列表</span><br><span class="line">请求方式：GET</span><br><span class="line">参数说明</span><br><span class="line">- keyword: 模糊查找的关键字。[选填]</span><br><span class="line">- enable: 启用状态[1-启用 2-禁用]。[选填]</span><br><span class="line">- offset: 获取位置偏移，从 0 开始。[选填]</span><br><span class="line">- limit: 每次获取返回的条数，缺省为 20 条，最大不超过 100。 [选填]</span><br><span class="line">响应内容</span><br><span class="line">HTTP/1.1 200 OK</span><br><span class="line">&#123;</span><br><span class="line">    &quot;count&quot;:100,</span><br><span class="line">    &quot;items&quot;:[</span><br><span class="line">        &#123;</span><br><span class="line">            &quot;id&quot; : &quot;01234567-89ab-cdef-0123-456789abcdef&quot;,</span><br><span class="line">            &quot;name&quot; : &quot;example&quot;,</span><br><span class="line">            &quot;created_time&quot;: 1496676420000,</span><br><span class="line">            &quot;updated_time&quot;: 1496676420000,</span><br><span class="line">            ...</span><br><span class="line">        &#125;,</span><br><span class="line">        ...</span><br><span class="line">    ]</span><br><span class="line">&#125;</span><br><span class="line">失败响应</span><br><span class="line">HTTP/1.1 403 UC/AUTH_DENIED</span><br><span class="line">Content-Type: application/json</span><br><span class="line">&#123;</span><br><span class="line">    &quot;code&quot;: &quot;INVALID_ARGUMENT&quot;,</span><br><span class="line">    &quot;message&quot;: &quot;&#123;error message&#125;&quot;,</span><br><span class="line">    &quot;cause&quot;: &quot;&#123;cause message&#125;&quot;,</span><br><span class="line">    &quot;request_id&quot;: &quot;01234567-89ab-cdef-0123-456789abcdef&quot;,</span><br><span class="line">    &quot;host_id&quot;: &quot;&#123;server identity&#125;&quot;,</span><br><span class="line">    &quot;server_time&quot;: &quot;2014-01-01T12:00:00Z&quot;</span><br><span class="line">&#125;</span><br><span class="line">错误代码</span><br><span class="line">- 403 UC/AUTH_DENIED    授权受限</span><br></pre></td></tr></table></figure>
<h1 id="参数接收"><a href="#参数接收" class="headerlink" title="参数接收"></a>参数接收</h1><p>本篇文章主要说下接口的数据参数到底该如何接收，我们知道一个http请求最重要的意义就是将数据在服务器上进行传入与传出，本章主要讲的也就是传入。一次请求传递参数的方式主要有 URL路径中、请求头中、请求体中还有通过cookie等，下面我们分别对几种方式进行讲解。</p>
<h2 id="MediaType的选择"><a href="#MediaType的选择" class="headerlink" title="MediaType的选择"></a>MediaType的选择</h2><p>MediaType即是Internet Media Type，互联网媒体类型；也叫做MIME类型，在Http协议消息头中，使用Content-Type来表示具体请求中的媒体类型信息。</p>
<p>对于POST、PUT、PATCH这种HTTP方法，统一使用 application/json，将参数放在请求体中以JSON格式传递至服务器<br>对于GET、DELETE的HTTP方法，使用默认类型（application/x-www-form-urlencoded）<br>★备注<br>特殊情况特殊考虑，例如进行文件上传时，使用 multipart/form-data类型等</p>
<h2 id="路径参数"><a href="#路径参数" class="headerlink" title="路径参数"></a>路径参数</h2><p>对应spring mvc框架中@PathVariable注解</p>
<p>接收参数方式为：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">public ResponseMessage get(@PathVariable(&quot;customerId&quot;)int customerId)&#123;</span><br><span class="line">	//...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>
<h2 id="请求头参数"><a href="#请求头参数" class="headerlink" title="请求头参数"></a>请求头参数</h2><p>对应spring mvc框架中@RequestHeader注解</p>
<p>对于提供给APP（android、ios、pc） 的接口我们可能需要关注一些调用信息，例如 用户登录信息、调用来源、app版本号、api的版本号、安全验证信息 等等，我们将这些信息放入头信息（HTTP HEAD中），下面给出在参数命名的例子：</p>
<p>Access-Token 用户的登录token（用于置换用户登录信息）<br>Api-Version api的版本号<br>App-Version app版本号<br>Call-Source 调用来源(IOS、ANDROID、PC、WECHAT、WEB)<br>Authorization 安全校验参数（后面会有文章详细介绍该如何做安全校验）<br>这时你可能会思考一下几个问题：</p>
<p>为什么需要收集 api版本号、app版本号、调用来源这些信息呢？<br>这里解释下，主要有几个原因：<br>①方便线上环境定位问题，这也是一个重要的原因（我们后面会讲通过切面全局打印非GET请求的接口调用日志）。<br>②我们可以通过这些参数信息处理我们的业务逻辑，而没有必要在用到的时候我们才想起来让调用者将信息传递过来，导致同一功能性的参数，参数名和参数值不统一的情况发生。<br>是每个接口都要这些参数么？<br>是的，建议将所有的接口都传递上述参数信息。<br>怎么做这些参数的校验呢？<br>你可以写个拦截器，统一校验你的接口中全局的header参数<br>★备注 </p>
<ul>
<li>Header参数大小写不敏感，所以参数Access-Token和ACCESS-TOKEN是一个参数</li>
</ul>
<h2 id="请求体参数"><a href="#请求体参数" class="headerlink" title="请求体参数"></a>请求体参数</h2><p>参数传递分为了大体两种 URL请求查询参数、请求体参数，对于请求体参数我们选择以JSON格式传递过来，URL请求查询参数、请求体参数这两种方式分别对应了spring mvc框架中的 @RequestParam、@RequestBody两个注解进行修饰。<br>我们下面以添加一个用户举例，用POSTMAN截图如下：</p>
<p><img src="http://upload-images.jianshu.io/upload_images/7477749-c6fdcdc835d413f7?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="创建用户"></p>
<h2 id="开发实例"><a href="#开发实例" class="headerlink" title="开发实例"></a>开发实例</h2><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br></pre></td><td class="code"><pre><span class="line">import javax.validation.Valid;</span><br><span class="line"></span><br><span class="line">import org.springframework.beans.factory.annotation.Autowired;</span><br><span class="line">import org.springframework.http.HttpStatus;</span><br><span class="line">import org.springframework.web.bind.annotation.DeleteMapping;</span><br><span class="line">import org.springframework.web.bind.annotation.GetMapping;</span><br><span class="line">import org.springframework.web.bind.annotation.PathVariable;</span><br><span class="line">import org.springframework.web.bind.annotation.PostMapping;</span><br><span class="line">import org.springframework.web.bind.annotation.PutMapping;</span><br><span class="line">import org.springframework.web.bind.annotation.RequestBody;</span><br><span class="line">import org.springframework.web.bind.annotation.RequestMapping;</span><br><span class="line">import org.springframework.web.bind.annotation.RequestParam;</span><br><span class="line">import org.springframework.web.bind.annotation.ResponseStatus;</span><br><span class="line">import org.springframework.web.bind.annotation.RestController;</span><br><span class="line"></span><br><span class="line">import com.zhuma.demo.comm.model.po.User;</span><br><span class="line">import com.zhuma.demo.user.service.user.UserService;</span><br><span class="line">import com.github.pagehelper.PageInfo;</span><br><span class="line"></span><br><span class="line">/**</span><br><span class="line"> * 用户管理控制器</span><br><span class="line"> */</span><br><span class="line">@RestController</span><br><span class="line">@RequestMapping(&quot;/users&quot;)</span><br><span class="line">public class UserController &#123;</span><br><span class="line"></span><br><span class="line">    private final UserService userService;</span><br><span class="line"></span><br><span class="line">    @Autowired</span><br><span class="line">    public UserController(UserService userService) &#123;</span><br><span class="line">        this.userService = userService;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @GetMapping</span><br><span class="line">    public PageInfo&lt;User&gt; getUserList(@RequestParam(name=&quot;pageNum&quot;, defaultValue=&quot;1&quot;) Integer pageNum, </span><br><span class="line">                                      @RequestParam(name=&quot;pageSize&quot;, defaultValue=&quot;10&quot;) Integer pageSize,</span><br><span class="line">                                        @RequestParam(name=&quot;queryUser&quot;) User queryUser) &#123;</span><br><span class="line">        return userService.pageList(queryUser, pageNum, pageSize);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @GetMapping(&quot;/&#123;userId&#125;&quot;)</span><br><span class="line">    User getUser(@PathVariable(&quot;userId&quot;) Long userId) &#123;</span><br><span class="line">        return userService.getUserById(userId);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @PostMapping</span><br><span class="line">    @ResponseStatus(HttpStatus.CREATED)</span><br><span class="line">    public User addUser(@Valid @RequestBody User user) &#123;</span><br><span class="line">        return userService.register(user);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @PutMapping</span><br><span class="line">    public User updateUser(@RequestBody User user) &#123;</span><br><span class="line">        return userService.updateDbAndCache(user);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @DeleteMapping(&quot;/&#123;userId&#125;&quot;)</span><br><span class="line">    @ResponseStatus(HttpStatus.NO_CONTENT)</span><br><span class="line">    void deleteUser(@PathVariable(&quot;userId&quot;) Long userId) &#123;</span><br><span class="line">        userService.deleteUserById(userId);</span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>上面我们截取一个管理用户的功能控制器，其中可能有一些你不了解的注解，例如@Valid、@ResponseStatus，@Valid一般配合参数校验使用，@ResponseStatus直接修饰目标方法，不管是否触发异常，都会返回指定的异常和错误码，这里我们主要看@GetMapping、@PostMapping、 @PutMapping、@DeleteMapping 分别处理查询、修改、删除功能，@RequestParam、@RequestBody 分别表示 查询参数、json body请求体参数。</p>
<h1 id="返回值"><a href="#返回值" class="headerlink" title="返回值"></a>返回值</h1><h2 id="格式选择"><a href="#格式选择" class="headerlink" title="格式选择"></a>格式选择</h2><p>返回格式目前主流的应该只有XML、JSON两种吧，这里我们不做对比，我们使用JSON作为接口的返回格式。</p>
<h2 id="数据返回格式"><a href="#数据返回格式" class="headerlink" title="数据返回格式"></a>数据返回格式</h2><p>数据的返回格式其实是个比较纠结的问题，在restful风格中很多文章都讲解使用的是http状态码控制请求的结果状态，例如：http状态码为200~300的时候，为正常状态，response响应体即为所需要返回的数据，404时代表没有查询到数据，响应体即为空，500为系统错误，响应体也为空等等，但是这种方式也是存在很大问题的，一是http状态码是有限的，而且每个状态码都已经被赋予特殊的含义，在企业开发中当接口遇到错误的时候，我们可能更希望将结果状态码标记的更为详细，更利于前端开发者使用，毕竟写接口的目的也是方便前端使用，这样也可以降低前后端开发人员沟通成本。<br>下面给出我们在实际开发中使用的返回值统一格式：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br><span class="line">202</span><br><span class="line">203</span><br><span class="line">204</span><br><span class="line">205</span><br><span class="line">206</span><br><span class="line">207</span><br><span class="line">208</span><br><span class="line">209</span><br><span class="line">210</span><br><span class="line">211</span><br><span class="line">212</span><br><span class="line">213</span><br><span class="line">214</span><br><span class="line">215</span><br><span class="line">216</span><br><span class="line">217</span><br><span class="line">218</span><br><span class="line">219</span><br><span class="line">220</span><br><span class="line">221</span><br><span class="line">222</span><br><span class="line">223</span><br><span class="line">224</span><br><span class="line">225</span><br><span class="line">226</span><br><span class="line">227</span><br><span class="line">228</span><br><span class="line">229</span><br><span class="line">230</span><br><span class="line">231</span><br><span class="line">232</span><br><span class="line">233</span><br><span class="line">234</span><br><span class="line">235</span><br><span class="line">236</span><br><span class="line">237</span><br><span class="line">238</span><br><span class="line">239</span><br><span class="line">240</span><br><span class="line">241</span><br><span class="line">242</span><br><span class="line">243</span><br><span class="line">244</span><br><span class="line">245</span><br><span class="line">246</span><br><span class="line">247</span><br><span class="line">248</span><br><span class="line">249</span><br><span class="line">250</span><br><span class="line">251</span><br><span class="line">252</span><br><span class="line">253</span><br><span class="line">254</span><br><span class="line">255</span><br><span class="line">256</span><br><span class="line">257</span><br><span class="line">258</span><br></pre></td><td class="code"><pre><span class="line">public class ResponseMessage implements Serializable &#123;</span><br><span class="line">    private static final long serialVersionUID = 8992436576262574064L;</span><br><span class="line">    /**</span><br><span class="line">     * 是否成功</span><br><span class="line">     */</span><br><span class="line">    private boolean success;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 反馈数据</span><br><span class="line">     */</span><br><span class="line">    private Object data;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 反馈信息</span><br><span class="line">     */</span><br><span class="line">    private String message;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 响应码</span><br><span class="line">     */</span><br><span class="line">    private int code;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 过滤字段：指定需要序列化的字段</span><br><span class="line">     */</span><br><span class="line">    private transient Map&lt;Class&lt;?&gt;, Set&lt;String&gt;&gt; includes;</span><br><span class="line"></span><br><span class="line">    /**</span><br><span class="line">     * 过滤字段：指定不需要序列化的字段</span><br><span class="line">     */</span><br><span class="line">    private transient Map&lt;Class&lt;?&gt;, Set&lt;String&gt;&gt; excludes;</span><br><span class="line"></span><br><span class="line">    private transient boolean onlyData;</span><br><span class="line"></span><br><span class="line">    private transient String callback;</span><br><span class="line"></span><br><span class="line">    public Map&lt;String, Object&gt; toMap() &#123;</span><br><span class="line">        Map&lt;String, Object&gt; map = new HashMap&lt;&gt;();</span><br><span class="line">        map.put(&quot;success&quot;, this.success);</span><br><span class="line">        if (data != null)</span><br><span class="line">            map.put(&quot;data&quot;, this.getData());</span><br><span class="line">        if (message != null)</span><br><span class="line">            map.put(&quot;message&quot;, this.getMessage());</span><br><span class="line">        map.put(&quot;code&quot;, this.getCode());</span><br><span class="line">        return map;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    protected ResponseMessage() &#123;&#125;</span><br><span class="line">    protected ResponseMessage(String message) &#123;</span><br><span class="line">        this.code = 500;</span><br><span class="line">        this.message = message;</span><br><span class="line">        this.success = false;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    protected ResponseMessage(boolean success, Object data) &#123;</span><br><span class="line">        this.code = success ? 200 : 500;</span><br><span class="line">        this.data = data;</span><br><span class="line">        this.success = success;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    protected ResponseMessage(boolean success, Object data ,Object message) &#123;</span><br><span class="line">        this.code = success ? 200 : 500;</span><br><span class="line">        this.data = data;</span><br><span class="line">        this.success = success;</span><br><span class="line">        this.message = (String)message;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    protected ResponseMessage(boolean success, Object data, int code) &#123;</span><br><span class="line">        this(success, data);</span><br><span class="line">        this.code = code;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    public ResponseMessage include(Class&lt;?&gt; type, String... fields) &#123;</span><br><span class="line">        return include(type, Arrays.asList(fields));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public ResponseMessage include(Class&lt;?&gt; type, Collection&lt;String&gt; fields) &#123;</span><br><span class="line">        if (includes == null)</span><br><span class="line">            includes = new HashMap&lt;&gt;();</span><br><span class="line">        if (fields == null || fields.isEmpty()) return this;</span><br><span class="line">        fields.forEach(field -&gt; &#123;</span><br><span class="line">            if (field.contains(&quot;.&quot;)) &#123;</span><br><span class="line">                String tmp[] = field.split(&quot;[.]&quot;, 2);</span><br><span class="line">                try &#123;</span><br><span class="line">                    Field field1 = type.getDeclaredField(tmp[0]);</span><br><span class="line">                    if (field1 != null) &#123;</span><br><span class="line">                        include(field1.getType(), tmp[1]);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; catch (Throwable e) &#123;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                getStringListFormMap(includes, type).add(field);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public ResponseMessage exclude(Class&lt;?&gt; type, Collection&lt;String&gt; fields) &#123;</span><br><span class="line">        if (excludes == null)</span><br><span class="line">            excludes = new HashMap&lt;&gt;();</span><br><span class="line">        if (fields == null || fields.isEmpty()) return this;</span><br><span class="line">        fields.forEach(field -&gt; &#123;</span><br><span class="line">            if (field.contains(&quot;.&quot;)) &#123;</span><br><span class="line">                String tmp[] = field.split(&quot;[.]&quot;, 2);</span><br><span class="line">                try &#123;</span><br><span class="line">                    Field field1 = type.getDeclaredField(tmp[0]);</span><br><span class="line">                    if (field1 != null) &#123;</span><br><span class="line">                        exclude(field1.getType(), tmp[1]);</span><br><span class="line">                    &#125;</span><br><span class="line">                &#125; catch (Throwable e) &#123;</span><br><span class="line">                &#125;</span><br><span class="line">            &#125; else &#123;</span><br><span class="line">                getStringListFormMap(excludes, type).add(field);</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;);</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public ResponseMessage exclude(Collection&lt;String&gt; fields) &#123;</span><br><span class="line">        if (excludes == null)</span><br><span class="line">            excludes = new HashMap&lt;&gt;();</span><br><span class="line">        if (fields == null || fields.isEmpty()) return this;</span><br><span class="line">        Class&lt;?&gt; type;</span><br><span class="line">        if (data != null) type = data.getClass();</span><br><span class="line">        else return this;</span><br><span class="line">        exclude(type, fields);</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public ResponseMessage include(Collection&lt;String&gt; fields) &#123;</span><br><span class="line">        if (includes == null)</span><br><span class="line">            includes = new HashMap&lt;&gt;();</span><br><span class="line">        if (fields == null || fields.isEmpty()) return this;</span><br><span class="line">        Class&lt;?&gt; type;</span><br><span class="line">        if (data != null) type = data.getClass();</span><br><span class="line">        else return this;</span><br><span class="line">        include(type, fields);</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public ResponseMessage exclude(Class&lt;?&gt; type, String... fields) &#123;</span><br><span class="line">        return exclude(type, Arrays.asList(fields));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">    public ResponseMessage exclude(String... fields) &#123;</span><br><span class="line">        return exclude(Arrays.asList(fields));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public ResponseMessage include(String... fields) &#123;</span><br><span class="line">        return include(Arrays.asList(fields));</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    protected Set&lt;String&gt; getStringListFormMap(Map&lt;Class&lt;?&gt;, Set&lt;String&gt;&gt; map, Class&lt;?&gt; type) &#123;</span><br><span class="line">        Set&lt;String&gt; list = map.get(type);</span><br><span class="line">        if (list == null) &#123;</span><br><span class="line">            list = new HashSet&lt;&gt;();</span><br><span class="line">            map.put(type, list);</span><br><span class="line">        &#125;</span><br><span class="line">        return list;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public boolean isSuccess() &#123;</span><br><span class="line">        return success;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setSuccess(boolean success) &#123;</span><br><span class="line">        this.success = success;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public Object getData() &#123;</span><br><span class="line">        return data;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public ResponseMessage setData(Object data) &#123;</span><br><span class="line">        this.data = data;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    @Override</span><br><span class="line">    public String toString() &#123;</span><br><span class="line">        return JSON.toJSONStringWithDateFormat(this, DateTimeUtils.YEAR_MONTH_DAY_HOUR_MINUTE_SECOND);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public int getCode() &#123;</span><br><span class="line">        return code;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public ResponseMessage setCode(int code) &#123;</span><br><span class="line">        this.code = code;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public static ResponseMessage fromJson(String json) &#123;</span><br><span class="line">        return JSON.parseObject(json, ResponseMessage.class);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public Map&lt;Class&lt;?&gt;, Set&lt;String&gt;&gt; getExcludes() &#123;</span><br><span class="line">        return excludes;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public Map&lt;Class&lt;?&gt;, Set&lt;String&gt;&gt; getIncludes() &#123;</span><br><span class="line">        return includes;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public ResponseMessage onlyData() &#123;</span><br><span class="line">        setOnlyData(true);</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setOnlyData(boolean onlyData) &#123;</span><br><span class="line">        this.onlyData = onlyData;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public boolean isOnlyData() &#123;</span><br><span class="line">        return onlyData;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public ResponseMessage callback(String callback) &#123;</span><br><span class="line">        this.callback = callback;</span><br><span class="line">        return this;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String getCallback() &#123;</span><br><span class="line">        return callback;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public String getMessage() &#123;</span><br><span class="line">        return message;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public void setMessage(String message) &#123;</span><br><span class="line">        this.message = message;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public static ResponseMessage ok() &#123;</span><br><span class="line">        return ok(null);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public static ResponseMessage created(Object data) &#123;</span><br><span class="line">        return new ResponseMessage(true, data, 201);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public static ResponseMessage ok(Object data) &#123;</span><br><span class="line">        return new ResponseMessage(true, data);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public static ResponseMessage error(String message) &#123;</span><br><span class="line">        return new ResponseMessage(message);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    public static ResponseMessage error(String message, int code) &#123;</span><br><span class="line">        return new ResponseMessage(message).setCode(code);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure></p>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/RESTful/" rel="tag"># RESTful</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2018/08/31/Mysql FEDREATED存储引擎/" rel="next" title="Mysql FEDREATED存储引擎">
                <i class="fa fa-chevron-left"></i> Mysql FEDREATED存储引擎
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2018/09/06/Linux查询占用文件的进程/" rel="prev" title="Linux查询占用文件的进程">
                Linux查询占用文件的进程 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
        <!-- Go to www.addthis.com/dashboard to customize your tools -->
<div class="addthis_inline_share_toolbox">
  <script type = "text/javascript" src = "//s7.addthis.com/js/300/addthis_widget.js#pubid=ra-5b4c0089687a63d1" async = "async" ></script>
</div>

      
    </div>
  </div>


          </div>
          


          
  <div class="comments" id="comments">
    
      <div id="lv-container" data-id="city" data-uid="MTAyMC8zMzEyNC85Njgz"></div>
    
  </div>


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap" >
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="/images/avatar.png"
               alt="混饭" />
          <p class="site-author-name" itemprop="name">混饭</p>
           
              <p class="site-description motion-element" itemprop="description">重度拖延症患者(-__-)b</p>
          
        </div>
        <nav class="site-state motion-element">

          
            <div class="site-state-item site-state-posts">
            
              <a href="/archives/">
            
                <span class="site-state-item-count">52</span>
                <span class="site-state-item-name">日志</span>
              </a>
            </div>
          

          
            
            
            <div class="site-state-item site-state-categories">
              <a href="/categories/index.html">
                <span class="site-state-item-count">4</span>
                <span class="site-state-item-name">分类</span>
              </a>
            </div>
          

          
            
            
            <div class="site-state-item site-state-tags">
              <a href="/tags/index.html">
                <span class="site-state-item-count">45</span>
                <span class="site-state-item-name">标签</span>
              </a>
            </div>
          

        </nav>

        

        <div class="links-of-author motion-element">
          
            
              <span class="links-of-author-item">
                <a href="https://github.com/hf-hf" target="_blank" title="GitHub">
                  
                    <i class="fa fa-fw fa-github"></i>
                  
                    
                      GitHub
                    
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="https://gitee.com/hf-hf" target="_blank" title="Gitee">
                  
                    <i class="fa fa-fw fa-gitee"></i>
                  
                    
                      Gitee
                    
                </a>
              </span>
            
          
        </div>

        
        

        
        

        


      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-1"><a class="nav-link" href="#RESTful-API"><span class="nav-number">1.</span> <span class="nav-text">RESTful API</span></a></li><li class="nav-item nav-level-1"><a class="nav-link" href="#路径定义"><span class="nav-number">2.</span> <span class="nav-text">路径定义</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#版本号"><span class="nav-number">2.1.</span> <span class="nav-text">版本号</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#资源路径"><span class="nav-number">2.2.</span> <span class="nav-text">资源路径</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#请求方式"><span class="nav-number">2.3.</span> <span class="nav-text">请求方式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#查询参数"><span class="nav-number">2.4.</span> <span class="nav-text">查询参数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#状态码"><span class="nav-number">2.5.</span> <span class="nav-text">状态码</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#异常响应"><span class="nav-number">2.6.</span> <span class="nav-text">异常响应</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#请求参数"><span class="nav-number">2.7.</span> <span class="nav-text">请求参数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#响应参数"><span class="nav-number">2.8.</span> <span class="nav-text">响应参数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#一个完整的案例"><span class="nav-number">2.9.</span> <span class="nav-text">一个完整的案例</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#参数接收"><span class="nav-number">3.</span> <span class="nav-text">参数接收</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#MediaType的选择"><span class="nav-number">3.1.</span> <span class="nav-text">MediaType的选择</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#路径参数"><span class="nav-number">3.2.</span> <span class="nav-text">路径参数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#请求头参数"><span class="nav-number">3.3.</span> <span class="nav-text">请求头参数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#请求体参数"><span class="nav-number">3.4.</span> <span class="nav-text">请求体参数</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#开发实例"><span class="nav-number">3.5.</span> <span class="nav-text">开发实例</span></a></li></ol></li><li class="nav-item nav-level-1"><a class="nav-link" href="#返回值"><span class="nav-number">4.</span> <span class="nav-text">返回值</span></a><ol class="nav-child"><li class="nav-item nav-level-2"><a class="nav-link" href="#格式选择"><span class="nav-number">4.1.</span> <span class="nav-text">格式选择</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#数据返回格式"><span class="nav-number">4.2.</span> <span class="nav-text">数据返回格式</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy; 
  <span itemprop="copyrightYear">2019</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">混饭</span>

  
</div>


  <div class="powered-by">由 <a class="theme-link" href="https://coding.net/pages">Hosted by CODING Pages</a> 强力驱动</div>



        
<div class="busuanzi-count">
  <script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

  
    <span class="site-uv">
      <i class="fa fa-user"></i>
      <span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
      
    </span>
  

  
    <span class="site-pv">
      <i class="fa fa-eye"></i>
      <span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
      
    </span>
  
</div>








        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  <script type="text/javascript" src="//cdn.jsdelivr.net/jquery/2.1.3/jquery.min.js"></script>

  
  <script type="text/javascript" src="//cdn.jsdelivr.net/fastclick/1.0.6/fastclick.min.js"></script>

  
  <script type="text/javascript" src="//cdn.jsdelivr.net/jquery.lazyload/1.9.3/jquery.lazyload.min.js"></script>

  
  <script type="text/javascript" src="//cdn.jsdelivr.net/velocity/1.2.3/velocity.min.js"></script>

  
  <script type="text/javascript" src="//cdn.jsdelivr.net/velocity/1.2.3/velocity.ui.min.js"></script>

  
  <script type="text/javascript" src="//cdn.jsdelivr.net/fancybox/2.1.5/jquery.fancybox.pack.js"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.2"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.2"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.2"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.2"></script>



  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.2"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.2"></script>


  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.2"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.2"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.2"></script>





  


  




	





  





  
    <script type="text/javascript">
      (function(d, s) {
        var j, e = d.getElementsByTagName(s)[0];
        if (typeof LivereTower === 'function') { return; }
        j = d.createElement(s);
        j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
        j.async = true;
        e.parentNode.insertBefore(j, e);
      })(document, 'script');
    </script>
  








  




  
  
  
    
  
  <link rel="stylesheet" href="//cdn.bootcss.com/instantsearch.js/1.5.0/instantsearch.min.css">

  
  
    
  
  <script src="//cdn.bootcss.com/instantsearch.js/1.5.0/instantsearch.min.js"></script>
  

  <script src="/js/src/algolia-search.js?v=5.1.2"></script>



  

  
  <script src="https://cdn1.lncld.net/static/js/av-core-mini-0.6.4.js"></script>
  <script>AV.initialize("FbdjjSByqhjHC2t0f5DiTzXi-gzGzoHsz", "EhyT8E3CKzF9CQcem5hx7ftx");</script>
  <script>
    function showTime(Counter) {
      var query = new AV.Query(Counter);
      var entries = [];
      var $visitors = $(".leancloud_visitors");

      $visitors.each(function () {
        entries.push( $(this).attr("id").trim() );
      });

      query.containedIn('url', entries);
      query.find()
        .done(function (results) {
          var COUNT_CONTAINER_REF = '.leancloud-visitors-count';

          if (results.length === 0) {
            $visitors.find(COUNT_CONTAINER_REF).text(0);
            return;
          }

          for (var i = 0; i < results.length; i++) {
            var item = results[i];
            var url = item.get('url');
            var time = item.get('time');
            var element = document.getElementById(url);

            $(element).find(COUNT_CONTAINER_REF).text(time);
          }
          for(var i = 0; i < entries.length; i++) {
            var url = entries[i];
            var element = document.getElementById(url);
            var countSpan = $(element).find(COUNT_CONTAINER_REF);
            if( countSpan.text() == '') {
              countSpan.text(0);
            }
          }
        })
        .fail(function (object, error) {
          console.log("Error: " + error.code + " " + error.message);
        });
    }

    function addCount(Counter) {
      var $visitors = $(".leancloud_visitors");
      var url = $visitors.attr('id').trim();
      var title = $visitors.attr('data-flag-title').trim();
      var query = new AV.Query(Counter);

      query.equalTo("url", url);
      query.find({
        success: function(results) {
          if (results.length > 0) {
            var counter = results[0];
            counter.fetchWhenSave(true);
            counter.increment("time");
            counter.save(null, {
              success: function(counter) {
                var $element = $(document.getElementById(url));
                $element.find('.leancloud-visitors-count').text(counter.get('time'));
              },
              error: function(counter, error) {
                console.log('Failed to save Visitor num, with error message: ' + error.message);
              }
            });
          } else {
            var newcounter = new Counter();
            /* Set ACL */
            var acl = new AV.ACL();
            acl.setPublicReadAccess(true);
            acl.setPublicWriteAccess(true);
            newcounter.setACL(acl);
            /* End Set ACL */
            newcounter.set("title", title);
            newcounter.set("url", url);
            newcounter.set("time", 1);
            newcounter.save(null, {
              success: function(newcounter) {
                var $element = $(document.getElementById(url));
                $element.find('.leancloud-visitors-count').text(newcounter.get('time'));
              },
              error: function(newcounter, error) {
                console.log('Failed to create');
              }
            });
          }
        },
        error: function(error) {
          console.log('Error:' + error.code + " " + error.message);
        }
      });
    }

    $(function() {
      var Counter = AV.Object.extend("Counter");
      if ($('.leancloud_visitors').length == 1) {
        addCount(Counter);
      } else if ($('.post-title-link').length > 1) {
        showTime(Counter);
      }
    });
  </script>



  

  

  

  

  

</body>
</html>
